'''
Board class.
Board data:
  1=red, -1=blue, 0=empty
  first dim is column , 2nd is row:
     pieces[1][7] is the square in column 2,
     at the opposite end of the board in row 8.
Squares are stored and manipulated as (x,y) tuples.
x is the column, y is the row.
'''
import numpy as np


class Board():

    # list of all 6 directions on the board, as (x,y) offsets
    __directions = [(1, 0), (1, -1), (0, -1), (-1, 0), (-1, 1), (0, 1)]

    def __init__(self, n):
        "Set up initial board configuration."

        self.n = n
        # Create the empty board array.
        self.pieces = [None] * self.n
        for i in range(self.n):
            self.pieces[i] = [0] * self.n

        # used to check game result
        self.visit_status = np.zeros((self.n, self.n))
        self.winner = 0

    # add [][] indexer syntax to the Board
    def __getitem__(self, index):
        return self.pieces[index]

    def get_legal_moves(self, color):
        """Returns all the legal moves for the given color.
        (1 for white, -1 for black
        """
        moves = list()  # stores the legal moves.

        # Get all the hex that is empty.
        for y in range(self.n):
            for x in range(self.n):
                if self[x][y] == 0:
                    moves.append((x, y))
        return moves

    def has_legal_moves(self, color):
        for y in range(self.n):
            for x in range(self.n):
                if self[x][y] == 0:
                    return True
        return False

    def execute_move(self, move, color):
        self[move[0]][move[1]] = color

    def get_game_result(self):
        # Red
        # for all top tiles, check if they connect to bottom
        for idx in range(self.n):
            if (not self.visit_status[0][idx] and
                self[0][idx] == 1 and
                self.winner == 0
                ):
                self._dfs_color(0, idx, 1)
        # Blue
        # for all left tiles, check if they connect to right
        for idx in range(self.n):
            if (not self.visit_status[idx][0] and
                self[idx][0] == -1 and
                self.winner == 0
                ):
                self._dfs_color(idx, 0, -1)

        self.visit_status.fill(0)
        return self.winner

    def _dfs_color(self, x, y, color):

        # check if (x, y) inside the board
        if x < 0 or x >= self.n or y < 0 or y >= self.n:
            return

        if self[x][y] != color:
            return

        if self.visit_status[x][y]:
            return
        self.visit_status[x][y] = 1

        # win conditions
        if color == 1 and x == self.n-1:
            self.winner = color
        elif color == -1 and y == self.n-1:
            self.winner = color

        if self.winner != 0:
            return

        for dx, dy in self.__directions:
            xn, yn = x + dx, y + dy
            self._dfs_color(xn, yn, color)
